package com.color.admin.system.servie.impl;

import com.color.admin.common.core.constant.Constant;
import com.color.admin.common.core.exception.BaseException;
import com.color.admin.common.core.utils.web.StringUtils;
import com.color.admin.system.entity.SysDict;
import com.color.admin.system.entity.vo.dict.DictTreeVo;
import com.color.admin.system.entity.vo.dict.DictVo;
import com.color.admin.system.repository.DictRepository;
import com.color.admin.system.servie.DictService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author HaiQiu
 * @date 2022/1/18
 */
@Service
public class DictServiceImpl implements DictService {

    @Autowired
    private DictRepository dictRepository;

    /**
     * 顶级父级ID
     */
    public static final String TOP_PID = "0";

    @Override
    public void save(SysDict sysDict) {
        sysDict.setParentId(StringUtils.isBlank(sysDict.getParentId()) ? TOP_PID : sysDict.getParentId());
        sysDict.setCreateTime(new Date());
        sysDict.setUpdateTime(new Date());
        SysDict save = dictRepository.save(sysDict);
        if (ObjectUtils.isEmpty(save)) {
            throw new BaseException(Constant.INSERT_FAIL);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public DictVo saveRes(SysDict sysDict) {
        sysDict.setParentId(StringUtils.isBlank(sysDict.getParentId()) ? TOP_PID : sysDict.getParentId());
        sysDict.setCreateTime(new Date());
        sysDict.setUpdateTime(new Date());
        SysDict save = dictRepository.save(sysDict);
        if (ObjectUtils.isEmpty(save)) {
            throw new BaseException(Constant.INSERT_FAIL);
        }
        DictVo dictVo = new DictVo();
        BeanUtils.copyProperties(save, dictVo);
        return dictVo;
    }

    @Override
    public void update(SysDict sysDict) {
        if (ObjectUtils.isEmpty(sysDict)) {
            throw new BaseException("修改数据为空");
        }
        if (StringUtils.isBlank(sysDict.getId())) {
            throw new BaseException(Constant.ID_EXITS);
        }
        SysDict dict = dictRepository.findById(sysDict.getId()).orElseGet(SysDict::new);
        dict.setUpdateTime(new Date());
        dict.setCode(sysDict.getCode());
        dict.setName(sysDict.getName());
        dict.setDescription(sysDict.getDescription());
        dict.setSort(sysDict.getSort());
        dict.setParentId(StringUtils.isBlank(sysDict.getParentId()) ? TOP_PID : sysDict.getParentId());
        dict.setActive(sysDict.getActive());
        SysDict save = dictRepository.save(dict);
        if (ObjectUtils.isEmpty(save)) {
            throw new BaseException(Constant.UPDATE_FAIL);
        }
    }

    @Override
    public DictVo updateRes(SysDict sysDict) {
        if (ObjectUtils.isEmpty(sysDict)) {
            throw new BaseException("修改数据为空");
        }
        if (StringUtils.isBlank(sysDict.getId())) {
            throw new BaseException(Constant.ID_EXITS);
        }
        SysDict dict = dictRepository.findById(sysDict.getId()).orElseGet(SysDict::new);
        dict.setUpdateTime(new Date());
        dict.setCode(sysDict.getCode());
        dict.setName(sysDict.getName());
        dict.setDescription(sysDict.getDescription());
        dict.setSort(sysDict.getSort());
        dict.setParentId(StringUtils.isBlank(sysDict.getParentId()) ? TOP_PID : sysDict.getParentId());
        dict.setActive(sysDict.getActive());
        SysDict save = dictRepository.save(dict);
        if (ObjectUtils.isEmpty(save)) {
            throw new BaseException(Constant.UPDATE_FAIL);
        }
        DictVo dictVo = new DictVo();
        BeanUtils.copyProperties(save, dictVo);
        return dictVo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Set<String> dictIds) {
        if (CollectionUtils.isEmpty(dictIds)) {
            throw new BaseException(Constant.ID_EXITS);
        }
        Set<String> dictAllIds = getDictAllIds(dictIds);
        if (dictRepository.deleteAllByIdIn(dictAllIds) == 0) {
            throw new BaseException(Constant.DELETE_FAIL);
        }
    }

    /**
     * 递归查询数据ID
     *
     * @param ids 递归ID
     * @return ID集合
     */
    private Set<String> getDictAllIds(Set<String> ids) {
        List<SysDict> dicts = dictRepository.findAllByParentIdIn(ids);
        if (!CollectionUtils.isEmpty(dicts)) {
            Set<String> childrenIds = dicts.stream().map(SysDict::getId).collect(Collectors.toSet());
            ids.addAll(childrenIds);
            getDictAllIds(childrenIds);
        }
        return ids;
    }

    @Override
    public SysDict get(String dictId) {
        SysDict sysDict = dictRepository.findById(dictId).orElseGet(SysDict::new);
        return sysDict;
    }

    @Override
    public Object list(Object o) {
        return null;
    }

    @Override
    public List<DictTreeVo> tree() {
        List<SysDict> dictList = dictRepository.findAll(Sort.by("sort"));
        if (!CollectionUtils.isEmpty(dictList)) {

            List<DictTreeVo> treeVos = dictList.stream().map(sysDict -> {
                DictTreeVo vo = new DictTreeVo();
                BeanUtils.copyProperties(sysDict, vo);
                return vo;
            }).collect(Collectors.toList());

            List<DictTreeVo> treeData = new ArrayList<>();
            treeVos.forEach(treeVo -> {
                if (treeVo.getParentId().equals(TOP_PID)) {
                    treeData.add(getChildrenData(treeVo, treeVos));
                }
            });
            return treeData;
        }
        return null;
    }

    private DictTreeVo getChildrenData(DictTreeVo vo, List<DictTreeVo> treeVos) {
        treeVos.forEach(child -> {
            if (child.getParentId().equals(vo.getId())) {
                vo.getChildren().add(getChildrenData(child, treeVos));
            }
        });
        return vo;
    }
}
